﻿using Framework;
using Framework.Models;
using Koala.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Koala.JiraTool.ScheduledTasks.Controls
{
    internal partial class ScheduledItemControl : UserControl, ITransientDependency
    {
        private readonly IDataPersistence _dataPersistence;

        public delegate void TaskHandler(IList<TaskInfo> taskInfos);

        #region Field

        private TaskHandler _eventHandler = list => { };

        public event TaskHandler TaskRun
        {
            add { _eventHandler += value; }
            remove { _eventHandler -= value; }
        }

        private TimeSpan[] _timeSpans;
        private CancellationTokenSource _tokenSource;

        #endregion Field

        #region Constructor

        public ScheduledItemControl()
            : this(null, null)
        {
        }

        public ScheduledItemControl(Lazy<TaskListControl> taskListControl, IDataPersistence dataPersistence)
        {
            _dataPersistence = dataPersistence;
            if (DesignMode)
            {
                InitializeComponent();
            }
            else
            {
                InitializeComponent(taskListControl.Value);
            }
        }

        #endregion Constructor

        #region Public Method

        public void SetControl(ScheduledItemSettings scheduledItemSettings, params string[] taskStatus)
        {
            taskListControl.Name = Name + "_" + taskListControl.Name;
            taskListControl.SetTaskStatus(taskStatus);
            txtTime.Text = scheduledItemSettings.Time;
            cbAutoRun.Checked = scheduledItemSettings.StartAutoRun;
            Stop();
        }

        public void Run()
        {
            SaveSettings();
            var list = taskListControl.GetList();
            if (list == null)
            {
                return;
            }
            _timeSpans = GetRunTimeSpan();
            var nextTimeSpan = GetNextTimeSpan();
            if (!nextTimeSpan.HasValue)
                return;
            txtTime.Enabled = false;
            taskListControl.SetControl(false);
            _tokenSource = new CancellationTokenSource();
            StartTimer(nextTimeSpan.Value, list);
        }

        public void Stop()
        {
            if (_tokenSource == null)
                return;
            _tokenSource.Cancel(false);
            txtTime.Enabled = true;
            taskListControl.SetControl(true);
            lblTime.Text = string.Empty;
        }

        #endregion Public Method

        #region Event

        private void cbAutoRun_CheckedChanged(object sender, EventArgs e)
        {
            SaveSettings();
        }

        #endregion Event

        #region Private Method

        private void StartTimer(TimeSpan timeSpan, IList<TaskInfo> taskInfos)
        {
            var newTime = new TimeSpan(timeSpan.Ticks);
            var token = _tokenSource.Token;
            var task = new Task(() =>
            {
                while (newTime.TotalSeconds > 0)
                {
                    if (_tokenSource.IsCancellationRequested)
                    {
                        throw new OperationCanceledException(token);
                    }
                    newTime = newTime.Subtract(new TimeSpan(0, 0, 1));
                    Invoke(new Action(() =>
                    {
                        lblTime.Text = newTime.ToString();
                    }));
                    Thread.Sleep(1000);
                }
            }, token);
            task.Start();
            task.ContinueWith(t =>
            {
                if (t.IsCanceled)
                    return;
                _eventHandler(taskInfos);
                Run();
            });
        }

        private TimeSpan? GetNextTimeSpan()
        {
            if (!_timeSpans.Any())
            {
                return null;
            }
            var time = _timeSpans.First();
            var dayTime = DateTime.Now.TimeOfDay;
            return time.Subtract(new TimeSpan(dayTime.Hours, dayTime.Minutes, dayTime.Seconds));
        }

        private TimeSpan[] GetRunTimeSpan()
        {
            var timeSpans = new List<TimeSpan>();
            var strs = txtTime.Text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var str in strs)
            {
                TimeSpan result;
                if (TimeSpan.TryParse(str, out result))
                {
                    timeSpans.Add(result);
                }
            }
            var dateTime = DateTime.Now;
            var currentTime = dateTime.TimeOfDay;
            //过滤无法执行到的时间，并排序。
            return timeSpans.Where(model => model > currentTime).OrderBy(model => model.TotalMilliseconds).ToArray();
        }

        private void SaveSettings()
        {
            var settings = new ScheduledItemSettings
            {
                StartAutoRun = cbAutoRun.Checked,
                Time = txtTime.Text
            };
            _dataPersistence.Save(Name + "_Settings", settings);
        }

        #endregion Private Method

    }
}